# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1069.1.234 -> 1.1069.1.235 # arch/ia64/kernel/mca.c 1.41 -> 1.42 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 04/01/08 bjorn.helgaas@hp.com 1.1069.175.5 # Merge # -------------------------------------------- # 04/01/08 kaos@sgi.com 1.1069.1.235 # [PATCH] ia64: fix deadlock in ia64_mca_cmc_int_caller() # # smp_call_function() must not be called from interrupt context (can # deadlock on tasklist_lock). Use keventd to call smp_call_function(). # -------------------------------------------- # diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c Thu Jan 8 16:34:19 2004 +++ b/arch/ia64/kernel/mca.c Thu Jan 8 16:34:19 2004 @@ -36,6 +36,10 @@ * SAL 3.0 spec. * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, * added min save state dump, added INIT handler. + * + * 2003-12-08 Keith Owens + * smp_call_function() must not be called from interrupt context (can + * deadlock on tasklist_lock). Use keventd to call smp_call_function(). */ #include #include @@ -50,6 +54,7 @@ #include #include #include +#include #include #include @@ -154,6 +159,8 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size); +static struct tq_struct cmc_disable_tq, cmc_enable_tq; + /* * ia64_mca_log_sal_error_record * @@ -626,6 +633,36 @@ } /* + * ia64_mca_cmc_vector_disable_keventd + * + * Called via keventd (smp_call_function() is not safe in interrupt context) to + * disable the cmc interrupt vector. + * + * Note: needs preempt_disable() if you apply the preempt patch to 2.4. + */ +static void +ia64_mca_cmc_vector_disable_keventd(void *unused) +{ + ia64_mca_cmc_vector_disable(NULL); + smp_call_function(ia64_mca_cmc_vector_disable, NULL, 1, 0); +} + +/* + * ia64_mca_cmc_vector_enable_keventd + * + * Called via keventd (smp_call_function() is not safe in interrupt context) to + * enable the cmc interrupt vector. + * + * Note: needs preempt_disable() if you apply the preempt patch to 2.4. + */ +static void +ia64_mca_cmc_vector_enable_keventd(void *unused) +{ + smp_call_function(ia64_mca_cmc_vector_enable, NULL, 1, 0); + ia64_mca_cmc_vector_enable(NULL); +} + +/* * ia64_mca_init * * Do all the system level mca specific initialization. @@ -658,6 +695,9 @@ IA64_MCA_DEBUG("ia64_mca_init: begin\n"); + INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL); + INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL); + /* initialize recovery success indicator */ ia64_os_mca_recovery_successful = 0; @@ -1062,14 +1102,7 @@ cmc_polling_enabled = 1; spin_unlock(&cmc_history_lock); - - /* - * We rely on the local_irq_enable() above so - * that this can't deadlock. - */ - ia64_mca_cmc_vector_disable(NULL); - - smp_call_function(ia64_mca_cmc_vector_disable, NULL, 1, 0); + schedule_task(&cmc_disable_tq); /* * Corrected errors will still be corrected, but @@ -1163,19 +1196,7 @@ if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { printk(KERN_WARNING "%s: Returning to interrupt driven CMC handler\n", __FUNCTION__); - - /* - * The cmc interrupt handler enabled irqs, so - * this can't deadlock. - */ - smp_call_function(ia64_mca_cmc_vector_enable, NULL, 1, 0); - - /* - * Turn off interrupts before re-enabling the - * cmc vector locally. Make sure we get out. - */ - local_irq_disable(); - ia64_mca_cmc_vector_enable(NULL); + schedule_task(&cmc_enable_tq); cmc_polling_enabled = 0; } else {